
#include <BFile>
#include <BPainter>
#include <BStyle>
#include <BFont>
#include <BSystem>
#include <BCursor>
#include <BMessageBox>
#include <BFileDialog>
#include <BReadWrite>
#include <BGridLayout>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BApplication>
#include <BViewer>

#include "StringUtils.h"
#include "ClassConsole.h"
#include "ClassViewer.h"
#include "InvokeBoard.h"
#include "VariantBoard.h"
#include "VariantBox.h"
#include "ScriptStudio.h"

ScriptStudio::ScriptStudio(BWidget* parent) : BDialog(parent)
{
	this->setSize(800, 560);

	_variantButton = new BButton();
	_variantButton->hide();
	this->addChild(_variantButton);

	_itemMenu = new BMenu();
	BAction* openAction = _itemMenu->addAction("open");
	BMenu* addMenu = _itemMenu->addMenu("add");
	{
		BAction* addFileAction = addMenu->addAction("file");
		BAction* addFolderAction = addMenu->addAction("folder");
		BAction* addScriptAction = addMenu->addAction("script");

		connect(addFileAction, Signal_Triggered, &ScriptStudio::slotAddFileActionTrigger);
		connect(addFolderAction, Signal_Triggered, &ScriptStudio::slotAddFolderActionTrigger);
		connect(addScriptAction, Signal_Triggered, &ScriptStudio::slotAddScriptActionTrigger);
	}
	BMenu* newMenu = _itemMenu->addMenu("new");
	{
		BAction* newFileAction = newMenu->addAction("file");
		BAction* newFolderAction = newMenu->addAction("folder");
		BAction* newScriptAction = newMenu->addAction("script");
		connect(newFileAction, Signal_Triggered, &ScriptStudio::slotNewFileActionTrigger);
		connect(newFolderAction, Signal_Triggered, &ScriptStudio::slotNewFolderActionTrigger);
		connect(newScriptAction, Signal_Triggered, &ScriptStudio::slotNewScriptActionTrigger);
	}
	BAction* removeAction = _itemMenu->addAction("remove");
	BAction* browseAction = _itemMenu->addAction("browse");
	BAction* cleanAction = _itemMenu->addAction("clean");
	connect(openAction, Signal_Triggered, &ScriptStudio::slotOpenActionTrigger);
	connect(removeAction, Signal_Triggered, &ScriptStudio::slotRemoveActionTrigger);
	connect(browseAction, Signal_Triggered, &ScriptStudio::slotBrowseActionTrigger);
	connect(cleanAction, Signal_Triggered, &ScriptStudio::slotCleanActionTrigger);

	_toolBar = new BWidget(this);
	{
		_openButton = new BButton("open");
		_openButton->setForm(Form_IconAlone);
		_openButton->setTips("open script project");

		_saveButton = new BButton("save");
		_saveButton->setEnabled(false);
		_saveButton->setForm(Form_IconAlone);
		_saveButton->setTips("save all");

		_undoButton = new BButton("undo");
		_undoButton->setForm(Form_IconAlone);

		_redoButton = new BButton("redo");
		_redoButton->setForm(Form_IconAlone);

		_searchButton = new BButton("search");
		_searchButton->setCheckable(true);
		_searchButton->setForm(Form_IconAlone);
		_searchButton->setTips("search text");

		_buildButton = new BButton("build");
		_buildButton->setCheckable(true);
		_buildButton->setForm(Form_IconAlone);
		_buildButton->setTips("build script");

		_debugButton = new BButton("debug");
		_debugButton->setEnabled(false);
		_debugButton->setCheckable(true);
		_debugButton->setForm(Form_IconAlone);
		_debugButton->setTips("debug script");

		BHBoxLayout* debugLayout = new BHBoxLayout();
		debugLayout->setName("debug");
		debugLayout->setEnabled(false);
		debugLayout->setSpacing(3);
		{
			_debugResetButton = new BButton("reset");
			_debugResetButton->setForm(Form_IconAlone);
			_debugResetButton->setTips("reset script");

			_debugCallButton = new BButton("call");
			_debugCallButton->setForm(Form_IconAlone);
			_debugCallButton->setTips("start call function.");

			_debugRunButton = new BButton("run");
			_debugRunButton->setEnabled(false);
			_debugRunButton->setForm(Form_IconAlone);
			_debugRunButton->setTips("continue");

			_debugNextButton = new BButton("next");
			_debugNextButton->setEnabled(false);
			_debugNextButton->setForm(Form_IconAlone);
			_debugNextButton->setTips("next line");

			_debugStepButton = new BButton("step");
			_debugStepButton->setEnabled(false);
			_debugStepButton->setForm(Form_IconAlone);
			_debugStepButton->setTips("step inside");

			_debugStopButton = new BButton("stop");
			_debugStopButton->setEnabled(false);
			_debugStopButton->setForm(Form_IconAlone);
			_debugStopButton->setTips("stop debug");

			_functionComboBox = new BComboBox();
			_functionComboBox->setMinWidth(200);

			debugLayout->addWidget(_debugResetButton);
			debugLayout->addWidget(_debugCallButton);
			debugLayout->addWidget(_debugRunButton);
			debugLayout->addWidget(_debugNextButton);
			debugLayout->addWidget(_debugStepButton);
			debugLayout->addWidget(_debugStopButton);
			debugLayout->addWidget(_functionComboBox);
			debugLayout->addSpring();
		}

		BHBoxLayout* hlayout = new BHBoxLayout(_toolBar);
		hlayout->setSpacing(3);
		hlayout->addWidget(_openButton);
		hlayout->addWidget(_saveButton);
		hlayout->addSpacer(6);
		hlayout->addWidget(_undoButton);
		hlayout->addWidget(_redoButton);
		hlayout->addSpacer(6);
		hlayout->addWidget(_searchButton);
		hlayout->addSpacer(6);
		hlayout->addWidget(_buildButton);
		hlayout->addWidget(_debugButton);
		hlayout->addSpacer(6);
		hlayout->addLayout(debugLayout);
		hlayout->addSpring();
	}

	BHBoxLayout* splitLayout = new BHBoxLayout();
	splitLayout->setSplitable(true);
	splitLayout->setSpacing(5);
	{
		BVBoxLayout* leftLayout = new BVBoxLayout();
		{
			_treeLabel = new BLabel();

			_treeWidget = new BTreeWidget();

			_itemEdit = new BLineEdit(_treeWidget);
			_itemEdit->hide();

			_itemMenu->setParent(_treeWidget);

			leftLayout->addWidget(_treeLabel, 0);
			leftLayout->addWidget(_treeWidget);
		}

		BVBoxLayout* centerLayout = new BVBoxLayout();
		{
			_tabWidget = new BTabWidget();

			_outputTabWidget = new BTabWidget();
			{
				BTextEdit* outputBrowser = new BTextEdit();
				outputBrowser->setReadOnly(true);
				outputBrowser->setTitle("output");
				connect(outputBrowser, Signal_DoubleClicked, &ScriptStudio::slotOutputDoubleClicked);

				InvokeBoard* invokeBoard = new InvokeBoard();
				invokeBoard->setTitle("invokes");

				VariantBoard* variantBoard = new VariantBoard();
				variantBoard->setTitle("variants");
				
				_outputTabWidget->addTab(outputBrowser);
				_outputTabWidget->addTab(invokeBoard);
				_outputTabWidget->addTab(variantBoard);
			}
			centerLayout->addWidget(_tabWidget, 10);
			centerLayout->addWidget(_outputTabWidget);
			centerLayout->setSplitable(true);
			centerLayout->setSpacing(5);
		}

		splitLayout->addLayout(leftLayout, 1);
		splitLayout->addLayout(centerLayout, 5);
	}

	BVBoxLayout* layout = new BVBoxLayout(this);
	layout->addWidget(_toolBar, 0);
	layout->addLayout(splitLayout);

	connect(_openButton, Signal_Clicked, &ScriptStudio::slotOpenButtonClicked);
	connect(_saveButton, Signal_Clicked, &ScriptStudio::slotSaveButtonClicked);
	connect(_undoButton, Signal_Clicked, &ScriptStudio::slotUndoButtonClicked);
	connect(_redoButton, Signal_Clicked, &ScriptStudio::slotRedoButtonClicked);
	connect(_searchButton, Signal_Toggled, &ScriptStudio::slotSearchButtonToggled);
	connect(_buildButton, Signal_Toggled, &ScriptStudio::slotBuildButtonToggled);
	connect(_debugButton, Signal_Toggled, &ScriptStudio::slotDebugButtonToggled);
	connect(_debugResetButton, Signal_Clicked, &ScriptStudio::slotDebugResetButtonClicked);
	connect(_debugCallButton, Signal_Clicked, &ScriptStudio::slotDebugCallButtonClicked);
	connect(_debugRunButton, Signal_Clicked, &ScriptStudio::slotDebugRunButtonClicked);
	connect(_debugNextButton, Signal_Clicked, &ScriptStudio::slotDebugNextButtonClicked);
	connect(_debugStepButton, Signal_Clicked, &ScriptStudio::slotDebugStepButtonClicked);
	connect(_debugStopButton, Signal_Clicked, &ScriptStudio::slotDebugStopButtonClicked);
	connect(_functionComboBox, Signal_ValueChanged, &ScriptStudio::slotDebugFunctionChanged);

	connect(_itemEdit, Signal_Focused, &ScriptStudio::slotItemEditFocused);
	connect(_itemEdit, Signal_TextEdited, &ScriptStudio::slotItemTextEdited);
	connect(_itemEdit, Signal_EditFinished, &ScriptStudio::slotItemEditFinished);

	connect(_treeWidget, Signal_ItemSelected, &ScriptStudio::slotTreeItemSelected);
	connect(_treeWidget, Signal_ItemClicked, &ScriptStudio::slotTreeItemClicked);
	connect(_treeWidget, Signal_ItemDoubleClicked, &ScriptStudio::slotTreeItemDoubleClicked);
	connect(_treeWidget, Signal_RightClicked, &ScriptStudio::slotTreeWidgetRightClicked);
	connect(_treeWidget, Signal_Frame, &ScriptStudio::slotTreeWidgetFramed);
	connect(_tabWidget, Signal_CurrentChanged, &ScriptStudio::slotCurrentTabChanged);

	connect("popup-variant-button", &ScriptStudio::slotPopupVariantButton);
}
ScriptStudio::~ScriptStudio()
{
	if (BScript* script = _debugButton->asset())
	{
		if (script->running())
		{
			script->debug("stop");
		}
	}
}

bool ScriptStudio::loadProject(const BString& fileName)
{
	BFile file(fileName);
	if (!file.open(IO_ReadText))
		return false;

	BSonDocument document;
	BSonNode* project = document.read(file);
	if (!project || project->name() != "project")
		return false;

	BString filePath;
	for (int i = 0; i < project->childCount(); i++)
	{
		BSonNode* child = project->child(i);
		if (child->name() != "script")
			continue;
		filePath.reset();
		filePath << fileName.path() << '/' << child->attrib("file");
		BScriptHolder script = new BScript();
		initScript(script);
		if (!ReadFile(filePath, script))
			continue;
		script->setName(filePath.name());
		ScriptInfo* sinfo = script->asset();
		sinfo->fileName = filePath;
		BTreeItem* item = createScriptItem(script);
		_treeWidget->addTopItem(item);
		item->setSelected(true);
	}
	return true;
}
bool ScriptStudio::saveProject(const BString& fileName)
{
	BFile file(fileName);
	if (!file.open(IO_WriteText))
		return false;
	BSonNode* projectNode = new BSonNode("project");
	for (int i = 0; i < _treeWidget->topItemCount(); i++)
	{
		const BScript* script = _treeWidget->topItem(i)->asset();
		ScriptInfo* sinfo = script->asset();
		BString filePath = sinfo->fileName;
		filePath.remove(fileName.path());
		if (filePath.beginWith('/'))
			filePath.remove('/');
		BSonNode* scriptNode = new BSonNode("script");
		scriptNode->setAttrib("file", filePath);
		projectNode->addChild(scriptNode);
	}
	BSonDocument document;
	document.setFormat("\n{\n\n}\n");
	document.write(file, projectNode);
	return true;
}

void ScriptStudio::initScript(BScript* script)
{
	ScriptInfo* sinfo = new ScriptInfo();
	script->setAsset(sinfo);

	if (BClass* console = new BClass())
	{
		console->insertVariant(BTextEdit::TypeName(), "board");
		console->insertMethod("Console()", console_create);
		console->insertMethod("void output(string)", console_output);
		script->regist("Console", console);
	}
	if (BClass* viewer = new BClass())
	{
		viewer->insertVariant(BViewer::TypeName(), "viewer");
		viewer->insertMethod("Viewer()", Viewer_create);
		viewer->insertMethod("void show()", Viewer_show);
		script->regist("Viewer", viewer);
	}
	connect(script, Signal_Compiled, &ScriptStudio::slotScriptCompiled);
	connect(script, Signal_Breaked, &ScriptStudio::slotScriptBreaked);
	connect(script, Signal_Inited, &ScriptStudio::slotScriptInited);
	connect(script, Signal_Error, &ScriptStudio::slotScriptError);
}
BTreeItem* ScriptStudio::createScriptItem(BScript* script)
{
	BTreeItem* scriptItem = new BTreeItem(script->name());
	scriptItem->setAsset(script);
	ScriptInfo* sinfo = script->asset();

	BString backupPath;
	BApplication::GetCurrentPath(backupPath);
	BApplication::SetCurrentPath(sinfo->fileName.path());
	for (int i = 0; i < script->sourceCount(); i++)
	{
		BSource* source = script->source(i);
		{
			const BString& fileName = source->name();
			SourceInfo* srcinfo = new SourceInfo();
			srcinfo->entry = BEntry::Open(source->name());
			if (srcinfo->entry)
			{
				BString text;
				BFile::Load(source->name(), text);
				source->setText(text);
				if (fileName.endWith(".cs"))
				{
					srcinfo->compilable = true;
					source->dirty();
				}
			}
			source->setAsset(srcinfo);
		}
		BTreeItem* item = scriptItem->create(source->name());
		item->setAsset(source);
	}
	BApplication::SetCurrentPath(backupPath);
	return scriptItem;
}
BTextEdit* ScriptStudio::openTreeItem(BTreeItem* item)
{
	BTextEdit* edit = (BTextEdit*)_tabWidget->tabOfAsset(item->asset());
	if (!edit)
	{
		if (BSource* source = item->asset())
		{
			SourceEdit* sourceEdit = new SourceEdit();
			sourceEdit->setReadOnly(_debugRunButton->checked());
			sourceEdit->setAsset(source);
			connect(sourceEdit, Signal_TextEdited, &ScriptStudio::slotSourceTextEdited);
			connect(sourceEdit, "create-breakpoint", &ScriptStudio::slotCreateBreakpoint);
			connect(sourceEdit, "remove-breakpoint", &ScriptStudio::slotRemoveBreakpoint);
			edit = sourceEdit;
		}
		else if (BScript* script = item->asset())
		{
			ScriptBrowser* browser = new ScriptBrowser();
			browser->setAsset(script);
			browser->setReadOnly(true);
			connect(browser, "create-breakpoint", &ScriptStudio::slotCreateBreakpoint);
			connect(browser, "remove-breakpoint", &ScriptStudio::slotRemoveBreakpoint);
			edit = browser;
		}
		else if (BFile* file = item->asset())
		{
			BString text;
			if (!file->read(text))
			{
				BMessageBox::Critical("Error", "Load file failed.");
				return 0;
			}
			edit = new BTextEdit();
			edit->setText(text);
			edit->setAsset(item->asset());
			edit->setReadOnly(_debugRunButton->checked());
			//connect(edit, Signal_Edited, &ScriptStudio::slotTextEdited);
		}
		edit->setTitle(item->text());
		edit->setTitleIcon(item->icon());
	}
	_tabWidget->addTab(edit, true);
	_tabWidget->setCurrentWidget(edit);
	return edit;
}
void ScriptStudio::freshTreeItem(BTreeItem* item)
{
	BIcon* icon = 0;
	const BStyle* style = this->realStyle();
	if (BFolder* folder = item->asset())
	{
		icon = style->icon("filter");
	}
	else if (BScript* script = item->asset())
	{
		icon = style->icon("script");
	}
	else if (BSource* source = item->asset())
	{
		SourceInfo* srcinfo = source->asset();
		ScriptInfo* sinfo = source->script()->asset();
		BString fileName = sinfo->fileName.path();
		fileName << '/' << source->name();
		icon = BSystem::EntryIcon(fileName);
	}
	item->setIcon(icon);
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		freshTreeItem(child);
	}
}
void ScriptStudio::drawTreeItem(BPainter& painter, BTreeItem* item)
{
	if (BSource* source = item->asset())
	{
		SourceInfo* srcinfo = source->asset();
		if (srcinfo && srcinfo->entry.empty() && _warnImage)
		{
			BRect rect = item->iconRect();
			painter.drawImage(rect, _warnImage, true);
		}
	}
	else
	{
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			drawTreeItem(painter, child);
		}
	}
}
void ScriptStudio::collectDepends(BExp* exp, SourceInfo* srcinfo)
{
	if (exp->syntax == Syntax_Include)
	{
		BExp* fileExp = exp->params.first();
		if (fileExp && fileExp->syntax == Syntax_File)
		{
			srcinfo->depends.append(fileExp->name);
		}
	}
	for (int i = 0; i < exp->subs.size(); i++)
	{
		collectDepends(exp->subs[i], srcinfo);
	}
}
void ScriptStudio::dirtyDependSource(const BString& header)
{
	for (int i = 0; i < _treeWidget->topItemCount(); i++)
	{
		BTreeItem* topItem = _treeWidget->topItem(i);
		BScript* script = topItem->asset();
		for (int s = 0; i < script->sourceCount(); i++)
		{
			BSource* source = script->source(i);
			SourceInfo* srcinfo = source->asset();
			if (srcinfo->depends.contain(header))
			{
				source->dirty();
			}
		}
	}
}
void ScriptStudio::jumpToBreakpoint(BScript* script)
{
	BTextEdit* textEdit = 0;
	if (_breakpoint.size())
	{
		int pos = _breakpoint.find(':');
		if (pos < _breakpoint.size())
		{
			BString fileName = _breakpoint.substr(0, pos);
			BString numberStr = _breakpoint.substr(pos + 1, _breakpoint.size());
			_debugLine = numberStr.toInt();
			textEdit = (BTextEdit*)_tabWidget->tab(fileName);
		}
		else
		{
			_debugLine = _breakpoint.toInt();
			textEdit = (BTextEdit*)_tabWidget->tabOfAsset(script);
		}
	}
	if (_debugEdit != textEdit)
	{
		if (_debugEdit)
		{
			disconnect(_debugEdit, Signal_Frame);
			_debugEdit->fresh();
		}
		_debugEdit = textEdit;
		if (_debugEdit)
		{
			connect(_debugEdit, Signal_Frame, &ScriptStudio::slotDebugEditFramed);
		}
	}
	if (_debugEdit)
	{
		_tabWidget->setCurrentWidget(_debugEdit);
		_debugEdit->scrollToLine(_debugLine);
		_debugEdit->fresh();
	}
}
void ScriptStudio::updateEntrance(BScript* script)
{
	if (script)
	{
		_functionComboBox->clearItems();
		_functionComboBox->addItem(BString());
		BValue value;
		script->query("functions", value);
		BStringArray& funcNames = value;
		for (int i = 0; i < funcNames.size(); i++)
		{
			const BString& name = funcNames[i];
			BComboItem* item = _functionComboBox->addItem(name);
			if (name.contain("::"))
				item->setEnabled(false);
		}
	}
}
void ScriptStudio::freshScriptStack(BScript* script)
{
	script->query("stack", _stackValue);
	if (VariantBoard* board = (VariantBoard*)_outputTabWidget->tab("variants"))
	{
		board->setScript(script);
		board->freshStack(_stackValue);
	}
	if (InvokeBoard* board = (InvokeBoard*)_outputTabWidget->tab("invokes"))
	{
		board->setScript(script);
		board->freshStack(_stackValue);
	}
}
void ScriptStudio::freshVariantButton(const BVariant& var)
{
	BObject* obj = createMenuOrAction(var);
	if (BMenu* child = dynamic_cast<BMenu*>(obj))
		_variantButton->setMenu(child);
	else
		_variantButton->setAction((BAction*)obj);
}
BObject* ScriptStudio::createMenuOrAction(const BVariant& var)
{
	const BVariant* ptr = var.value();
	if (!ptr)
		ptr = &var;
	if (BClass* cls = ptr->value())
	{
		BString text;
		text << ptr->type() << " : " << ptr->name();
		BMenu* menu = new BMenu(text);
		for (int i = 0; i < cls->variantCount(); i++)
		{
			BObject* obj = createMenuOrAction(*cls->variant(i));
			if (BMenu* child = dynamic_cast<BMenu*>(obj))
				menu->addMenu(child);
			else
				menu->addAction((BAction*)obj);
		}
		return menu;
	}
	BString text;
	if (ptr != &var)
		text << "*";
	if (ptr->type().empty())
		text << "void";
	else
		text << ptr->type();
	text << ' ' << ptr->name() << " : ";
	BString str = StringOfValue(ptr->value());
	if (str.empty())
		text << "none";
	else
		text << str;
	return new BAction(text);
}

void ScriptStudio::slotOpenActionTrigger(BAction* action)
{
	if (BTreeItem* item = _itemMenu->asset())
	{
		openTreeItem(item);
	}
}
void ScriptStudio::slotAddFileActionTrigger(BAction* action)
{
	if (BTreeItem* item = _itemMenu->asset())
	{
		BTreeItem* scriptItem = item->root();
		BScript* script = scriptItem->asset();
		ScriptInfo* sinfo = script->asset();
		BString path = sinfo->fileName.path();
		if (!path.endWith('/'))
			path.append('/');
		BStringList fileNames = BFileDialog::OpenFiles("Add srcinfo file", path, "*.h;*.cpp");
		if (fileNames.empty())
			return;
		BString backup;
		BApplication::GetCurrentPath(backup);
		BApplication::SetCurrentPath(path);
		for (int i = 0; i < fileNames.size(); i++)
		{
			BString fileName = fileNames[i];
			fileName.remove(path);
			BSource* source = new BSource(fileName);
			{
				SourceInfo* srcinfo = new SourceInfo();
				if (fileName.endWith(".cs"))
				{
					srcinfo->compilable = true;
					source->dirty();
				}
				srcinfo->entry = BEntry::Open(fileName);
				if (srcinfo->entry)
				{
					BString text;
					BFile::Load(fileName, text);
					source->setText(text);
				}
				source->setAsset(srcinfo);
			}
			script->insertSource(source);

			BTreeItem* child = scriptItem->create(fileName);
			child->setAsset(source);
			freshTreeItem(child);
		}
		BApplication::GetCurrentPath(backup);
		sinfo->changed = true;
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotAddFolderActionTrigger(BAction* action)
{
	if (BTreeItem* item = _itemMenu->asset())
	{
		BTreeItem* scriptItem = item->root();
		BScript* script = scriptItem->asset();
		ScriptInfo* sinfo = script->asset();
		BString path = sinfo->fileName.path();
		if (!path.endWith('/'))
			path.append('/');
		BStringList fileNames = BFileDialog::OpenFiles("Add srcinfo file", path, "*.h;*.cpp");
		if (fileNames.empty())
			return;
		BString backup;
		BApplication::GetCurrentPath(backup);
		BApplication::SetCurrentPath(path);
		for (int i = 0; i < fileNames.size(); i++)
		{
			BString fileName = fileNames[i];
			fileName.remove(path);
			BSource* source = new BSource(fileName);
			{
				SourceInfo* srcinfo = new SourceInfo();
				if (fileName.endWith(".cs"))
				{
					srcinfo->compilable = true;
					source->dirty();
				}
				srcinfo->entry = BEntry::Open(fileName);
				if (srcinfo->entry)
				{
					BString text;
					BFile::Load(fileName, text);
					source->setText(text);
				}
				source->setAsset(srcinfo);
			}
			script->insertSource(source);

			BTreeItem* child = scriptItem->create(fileName);
			child->setAsset(source);
			freshTreeItem(child);
		}
		BApplication::GetCurrentPath(backup);
		sinfo->changed = true;
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotAddScriptActionTrigger(BAction* action)
{
	BStringList fileNames = BFileDialog::OpenFiles("Add srcinfo file", "", "*.bsf");
	if (fileNames.empty())
		return;
	for (int i = 0; i < fileNames.size(); i++)
	{
		const BString& fileName = fileNames[i];
		BString backup;
		BApplication::GetCurrentPath(backup);
		BApplication::SetCurrentPath(fileName.path());
		BScript* script = new BScript();
		initScript(script);
		if (ReadFile(fileName, script))
		{
			ScriptInfo* sinfo = script->asset();
			sinfo->fileName = fileName;
			if (script->name().empty())
			{
				script->setName(fileName.name());
			}
			BTreeItem* scriptItem = createScriptItem(script);
			_treeWidget->addTopItem(scriptItem);
			freshTreeItem(scriptItem);
		}
		else
		{
			BMessageBox::Warning("Error", "Load script failed");
		}
		BApplication::GetCurrentPath(backup);
		if (!_treeLabel->text().endWith('*'))
			_treeLabel->setText(_treeLabel->text() + '*');
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotNewFileActionTrigger(BAction* action)
{
	BString fileName("new-file");
	if (BTreeItem* parent = _itemMenu->asset())
	{
		BScript* script = parent->root()->asset();
		if (BFolder* folder = parent->asset())
		{
			fileName.prepend("/");
			fileName.prepend(folder->path());
		}
		if (!BFile::Create(fileName))
		{
			return;
		}
		BSource* source = new BSource(fileName);
		{
			SourceInfo* srcinfo = new SourceInfo();
			source->setAsset(srcinfo);
		}
		script->insertSource(source);

		BTreeItem* item = parent->create(fileName);
		item->setAsset(source);
		freshTreeItem(item);
		openTreeItem(item);
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotNewFolderActionTrigger(BAction* action)
{
	BTreeItem* parent = _itemMenu->asset();
	if (parent)
	{
		BString filePath("new-folder");
		int number = 0;
		while (1)
		{
			if (parent && !parent->child(filePath))
				break;
			if (!parent && !_treeWidget->topItem(filePath))
				break;
			filePath.reset();
			filePath << "filter" << ++number;
		}
		BFolder* dir = parent->asset();
		filePath.prepend('/');
		filePath.prepend(dir->path());
		BFolder::Create(filePath);
		BFolder* folder = new BFolder(filePath);
		BTreeItem* item = new BTreeItem(filePath.name());
		parent->addChild(item);
		item->setAsset(folder);
		freshTreeItem(item);
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotNewScriptActionTrigger(BAction* action)
{
	BString fileName = BFileDialog::OpenFile("Create Script", "data", "*.bsf,*bs");
	if (fileName.size())
	{
		if (BFile::Exist(fileName))
		{
			BString message;
			message << fileName << '\n' << "file is existing, you can add it.";
			BMessageBox::Warning("Warning", message);
			return;
		}
		if (!BFile::Create(fileName))
		{
			BString message;
			message << fileName << '\n' << "Create file failed : ";
			BMessageBox::Warning("Warning", message);
			return;
		}
		BScript* script = new BScript();
		initScript(script);
		ScriptInfo* sinfo = script->asset();
		sinfo->fileName = fileName;
		script->setName(fileName.name());
		WriteFile(fileName, script);
		BTreeItem* scriptItem = createScriptItem(script);
		_treeWidget->addTopItem(scriptItem);
		freshTreeItem(scriptItem);
	}
}
void ScriptStudio::slotRemoveActionTrigger(BAction* action)
{
	if (BTreeItem* item = _itemMenu->asset())
	{
		BScript* script = item->root()->asset();
		if (BSource* source = item->asset())
		{
			script->removeSource(source);
		}
		if (BFolder* folder = item->asset())
		{
			BFolder::Remove(folder->path());
		}
		if (BTreeItem* parent = item->parent())
		{
			parent->removeChild(item);
		}
		else
		{
			_treeWidget->removeTopItem(item);
		}
		ScriptInfo* sinfo = script->asset();
		sinfo->changed = true;
		_saveButton->setEnabled(true);
	}
}
void ScriptStudio::slotBrowseActionTrigger(BAction* action)
{
	if (BTreeItem* item = _itemMenu->asset())
	{
		BString path;
		if (BSource* source = item->asset())
		{
			path = source->name().path();
		}
		else if (BFolder* folder = item->asset())
			path = folder->path();
		BFileDialog::OpenFolder("", path);
	}
}
void ScriptStudio::slotCleanActionTrigger(BAction* action)
{
	BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output");
	_outputTabWidget->setCurrentWidget(output);
	output->setText("--------------- start clean -------------\n");
	if (BTreeItem* item = _itemMenu->asset())
	{
		BString text;
		if (BSource* source = item->asset())
		{
			SourceInfo* srcinfo = source->asset();
			if (!source->isdirty() && srcinfo->compilable)
			{
				source->dirty();
				text.reset();
				text << "clean " << source->name() << '\n';
				output->addText(text);
			}
		}
		if (BScript* script = item->asset())
		{
			for (int i = 0; i < script->sourceCount(); i++)
			{
				BSource* source = script->source(i);
				SourceInfo* srcinfo = source->asset();
				if (!source->isdirty() && srcinfo->compilable)
				{
					source->dirty();
					text.reset();
					text << "clean " << source->name() << '\n';
					output->addText(text);
				}
			}
			script->clear();
			text.reset();
			text << "clean " << script->name() << '\n';
			output->addText(text);
		}
	}
	output->addText("=========== clean finished ============\n");
}

void ScriptStudio::slotOpenButtonClicked()
{
	const BString& fileName = BFileDialog::OpenFile("Open Script Project", "data", ".bsp");
	if (fileName.empty())
		return;
	if (!fileName.endWith(".bsp"))
	{
		BString text = "Open Project Failed";
		text << "\nscript project file should end with .bsp.";
		BMessageBox::Warning("Error", text);
		return;
	}
	if (loadProject(fileName))
	{
		_treeLabel->setName(fileName);
		_treeLabel->setText(fileName.name());
		_treeLabel->setImage(BSystem::EntryImage(fileName));
		for (int i = 0; i < _treeWidget->topItemCount(); i++)
		{
			BTreeItem* topItem = _treeWidget->topItem(i);
			freshTreeItem(topItem);
		}
	}
	else
	{
		BMessageBox::Warning("Warning", "Open Project Failed");
	}
}
void ScriptStudio::slotSaveButtonClicked()
{
	for (int i = 0; i < _tabWidget->tabCount(); i++)
	{
		BWidget* widget = _tabWidget->tab(i);
		if (!widget->title().endWith('*'))
			continue;
		if (BSource* source = widget->asset())
		{
			ScriptInfo* sinfo = source->script()->asset();
			SourceInfo* srcinfo = source->asset();
			SourceEdit* edit = dynamic_cast<SourceEdit*>(widget);
			BString fileName = sinfo->fileName.path();
			fileName << '/' << source->name();
			if (BFile::Save(fileName, edit->text()))
			{
				source->setText(edit->text());
				if (srcinfo->compilable)
					source->dirty();
				else
					dirtyDependSource(source->name());
				BString title = edit->title();
				title -= '*';
				edit->setTitle(title);
			}
			else
			{
				BMessageBox::Critical("Error : Save source file failed", fileName);
				return;
			}
			for (int i = 0; i < srcinfo->exps.size(); i++)
			{
				collectDepends(srcinfo->exps[i], srcinfo);
			}
		}
	}
	for (int i = 0; i < _treeWidget->topItemCount(); i++)
	{
		BScript* script = _treeWidget->topItem(i)->asset();
		ScriptInfo* sinfo = script->asset();
		if (sinfo->changed)
		{
			if (WriteFile(sinfo->fileName, script))
			{
				sinfo->changed = false;
			}
			else
			{
				BMessageBox::Critical("Error : Save script file failed", sinfo->fileName);
				return;
			}
		}
	}
	if (_treeLabel->text().endWith('*'))
	{
		if (_treeLabel->name().empty())
		{
			const BString& fileName = BFileDialog::SaveFile("Save project : choose file name", "", "*.bsp");
			if (fileName.empty())
				return;
			_treeLabel->setName(fileName);
		}
		const BString& fileName = _treeLabel->name();
		if (saveProject(fileName))
		{
			_treeLabel->setText(fileName.name());
		}
	}
	_saveButton->setEnabled(false);
}
void ScriptStudio::slotUndoButtonClicked()
{

}
void ScriptStudio::slotRedoButtonClicked()
{

}
void ScriptStudio::slotSearchButtonToggled(BObject* object, const BValue& value)
{

}
void ScriptStudio::slotBuildButtonToggled(BObject* object, const BValue& value)
{
	if (_saveButton->enabled())
	{
		slotSaveButtonClicked();
	}
	bool checked = value;
	if (checked)
	{
		BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output");
		_outputTabWidget->setCurrentWidget(output);
		output->setText("------------- start build -------------\n");
		int successCount = 0;
		int failedCount = 0;
		for (int i = 0; i < _treeWidget->topItemCount(); i++)
		{
			BTreeItem* topItem = _treeWidget->topItem(i);
			BScript* script = topItem->asset();
			ScriptInfo* sinfo = script->asset();
			sinfo->buildCount = i;
			connect(script, Signal_Message, &ScriptStudio::slotScriptMessage);
			if (script->compile())
				successCount++;
			else
				failedCount++;
			disconnect(script, Signal_Message);
			if (_debugButton->asset() == script)
			{
				updateEntrance(script);
			}
		}
		BString message;
		message << "======== build sucess " << successCount << ", failed " << failedCount << " ========\n";
		output->addText(message);
		_buildButton->setChecked(false);
	}
}
void ScriptStudio::slotDebugButtonToggled(BObject* object, const BValue& value)
{
	BLayout* layout = _toolBar->layout("debug");
	BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output");
	BScript* script = _debugButton->asset();
	if (bool checked = value)
	{
		for (int i = 0; i < _tabWidget->tabCount(); i++)
		{
			BTextEdit* edit = dynamic_cast<BTextEdit*>(_tabWidget->tab(i));
			edit->setReadOnly(true);
		}
		script->setDebugging(true);
		layout->setEnabled(true);
		output->setText("------------- start debug -------------\n");
	}
	else
	{
		for (int i = 0; i < _tabWidget->tabCount(); i++)
		{
			BTextEdit* edit = dynamic_cast<BTextEdit*>(_tabWidget->tab(i));
			edit->setReadOnly(false);
		}
		script->setDebugging(false);
		if (_debugEdit)
		{
			_debugEdit->fresh();
			_breakpoint.clear();
			_debugEdit = 0;
			_debugLine = 0;
		}
		layout->setEnabled(false);
		output->addText("======== debug over ========\n");
	}
}
void ScriptStudio::slotDebugResetButtonClicked(BObject* object, const BValue& value)
{
	BScript* script = _debugButton->asset();
	script->reset();
	freshScriptStack(script);
}
void ScriptStudio::slotDebugCallButtonClicked(BObject* object, const BValue& value)
{
	if (BScript* script = _debugButton->asset())
	{
		_debugResetButton->setEnabled(false);
		_debugCallButton->setEnabled(false);
		_debugRunButton->setEnabled(true);
		_debugNextButton->setEnabled(true);
		_debugStepButton->setEnabled(true);
		_debugStopButton->setEnabled(true);
		BVariantArray vars;
		BHBoxLayout* hlayout = (BHBoxLayout*)_toolBar->layout("debug");
		int pos = hlayout->index(_functionComboBox) + 1;
		for (int i = pos; i < hlayout->count() - 1; i++)
		{
			VariantBox* varbox = (VariantBox*)hlayout->widget(i);
			vars.append(varbox->variant());
		}
		script->pcall(_functionComboBox->asset(), vars.size(), vars.data());
		for (int i = pos; i < hlayout->count() - 1; i++)
		{
			VariantBox* varbox = (VariantBox*)hlayout->widget(i);
			varbox->setVariant(vars(i - pos));
		}
		_breakpoint.clear();
		jumpToBreakpoint(script);
		freshScriptStack(script);
		_debugResetButton->setEnabled(true);
		_debugCallButton->setEnabled(true);
		_debugRunButton->setEnabled(false);
		_debugNextButton->setEnabled(false);
		_debugStepButton->setEnabled(false);
		_debugStopButton->setEnabled(false);
	}
}
void ScriptStudio::slotDebugRunButtonClicked(BObject* object, const BValue& value)
{
	BScript* script = _debugButton->asset();
	bool res = script->debug(BString());
}
void ScriptStudio::slotDebugNextButtonClicked()
{
	BString command;
	int pos = _breakpoint.find(':');
	if (pos < _breakpoint.size())
	{
		BString numberStr = _breakpoint.substr(pos + 1, _breakpoint.size());
		int number = numberStr.toInt();
		command.append(_breakpoint, 0, pos + 1);
		command.append(number + 1);
	}
	else
	{
		int number = _breakpoint.toInt();
		command = number + 1;
	}
	BScript* script = _debugButton->asset();
	bool res = script->debug(command);
}
void ScriptStudio::slotDebugStepButtonClicked()
{
	BScript* script = _debugButton->asset();
	bool res = script->debug("step");
}
void ScriptStudio::slotDebugStopButtonClicked()
{
	BScript* script = _debugButton->asset();
	bool res = script->debug("stop");
}
void ScriptStudio::slotDebugFunctionChanged(BObject* object, const BValue& value)
{
	BHBoxLayout* hlayout = (BHBoxLayout*)_toolBar->layout("debug");
	int pos = hlayout->index(_functionComboBox) + 1;
	while (pos < hlayout->count() - 1)
	{
		hlayout->remove(pos);
	}
	const BString& text = _functionComboBox->text();
	if (text.size())
	{
		int split = text.find(' ');
		BString type = text.substr(0, split);
		BString name = text.word(split + 1);
		_functionComboBox->setAsset(name);
		BString params = text.substr(text.find('(') + 1, text.rfind(')'));
		BStringList types = params.split(',');
		VariantBox* varbox = new VariantBox();
		varbox->setType(type);
		hlayout->insertWidget(pos++, varbox);
		for (int i = 0; i < types.size(); i++)
		{
			const BString& type = types[i];
			VariantBox* varbox = new VariantBox();
			varbox->setType(type);
			hlayout->insertWidget(pos++, varbox);
		}
	}
	else
	{
		_functionComboBox->setAsset(text);
	}
}
void ScriptStudio::slotDebugEditFramed(BObject* object, const BValue& value)
{
	if (BTextEdit* edit = (BTextEdit*)object)
	{
		BPainter painter(edit);
		BRect leftRect = edit->rect(Part_Left);
		BRect imageRect = edit->lineRect(_debugLine);
		if (_arrowImage)
		{
			imageRect.left() = leftRect.right();
			imageRect.right() = leftRect.right() + imageRect.height();
			imageRect.setSize(imageRect.size().wrap(_arrowImage->size()));
			painter.drawImage(imageRect, _arrowImage);
		}
		else
		{
			imageRect.left() = leftRect.right();
			imageRect.right() = leftRect.right() + imageRect.height();
			painter.setColor(0, 100, 120);
			painter.drawGraph(imageRect.align(Align_RightCenter, imageRect.size() / 2), Graph_Arrow_Right_Fill);
		}
	}
}
void ScriptStudio::slotPopupVariantButton(BObject* object, const BValue& value)
{
	const BVariantArray& stack = _stackValue;
	if (stack.size())
	{
		BVariant var;
		const BString& text = value;
		for (int i = 0; i < stack.size(); i++)
		{
			if (stack[i].name() == text)
			{
				var = stack[i];
				break;
			}
		}
		freshVariantButton(var);
		if (var.empty())
		{
			_variantButton->hide();
		}
		else
		{
			_variantButton->setSize(_variantButton->sizeHint());
			_variantButton->setPos(BCursor::GetPos(this));
			_variantButton->popup();
		}
	}
}

void ScriptStudio::slotScriptCompiled(BObject* object, const BValue& value)
{
	ScriptInfo* sinfo = object->asset();
	sinfo->changed = true;
	_saveButton->setEnabled(true);
}
void ScriptStudio::slotScriptMessage(BObject* object, const BValue& value)
{
	BScript* script = (BScript*)object;
	const BString& message = value;
	ScriptInfo* sinfo = script->asset();
	BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output");
	output->addText(sinfo->buildCount);
	output->addText('>');
	output->addText(message);
	if (!message.endWith('\n'))
	{
		output->addText('\n');
	}
}
void ScriptStudio::slotScriptBreaked(BObject* object, const BValue& value)
{
	BScript* script = (BScript*)object;
	_breakpoint = (const BString&)value;
	jumpToBreakpoint(script);
	freshScriptStack(script);
}
void ScriptStudio::slotScriptInited(BObject* object, const BValue& value)
{
	BScript* script = (BScript*)object;
	BWidget* widget = _outputTabWidget->tab("output");
	script->setValue("console.board", widget);
	if (BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output"))
	{
		BString text = script->name();
		text << "global variants inited.\n";
		output->addText(text);
	}
}
void ScriptStudio::slotScriptError(BObject* object, const BValue& value)
{
	BScript* script = (BScript*)object;
	const BString& message = value;
	if (BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output"))
	{
		output->addText(message);
		if (!message.endWith('\n'))
		{
			output->addText('\n');
		}
	}
	freshScriptStack(script);
	Button button = BMessageBox::Critical("Script Debug Error", message, Button_Cancel | Button_Close, Button_Close);
	if (button)
	{
		bool res = script->debug("stop");
	}
}

void ScriptStudio::slotTreeWidgetFramed(BObject* object, const BValue& value)
{
	BPainter painter(_treeWidget);
	for (int i = 0; i < _treeWidget->topItemCount(); i++)
	{
		BTreeItem* topItem = _treeWidget->topItem(i);
		drawTreeItem(painter, topItem);
	}
}
void ScriptStudio::slotTreeItemSelected(BObject* object, const BValue& value)
{
	if (!_debugButton->checked())
	{
		BTreeItem* item = value;
		BScript* script = item->root()->asset();
		if (_debugButton->asset() != script)
		{
			static BFont* font = new BFont("arial", 22);
			if (BTreeItem* scriptItem = _treeWidget->itemOfAsset(_debugButton->asset()))
			{
				scriptItem->setFont(0);
			}
			_debugButton->setEnabled(script);
			_debugButton->setAsset(script);
			updateEntrance(script);
			if (BTreeItem* scriptItem = _treeWidget->itemOfAsset(_debugButton->asset()))
			{
				scriptItem->setFont(font);
			}
		}
	}
}
void ScriptStudio::slotTreeItemClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (_itemEdit->asset() != item)
	{
		_itemEdit->setAsset(item);
		_pressedPos = BCursor::GetPos(_treeWidget);
		return;
	}
	if (item)
	{
		BPoint clickPos = BCursor::GetPos(_treeWidget);
		if ((clickPos - _pressedPos).length() > 5)
		{
			_itemEdit->setRect(item->textRect() + BSize(item->font()->size(), 0));
			_itemEdit->setText(item->text());
			_itemEdit->popup();
		}
		else
		{
			_itemEdit->setAsset(item);
			_pressedPos = clickPos;
		}
	}
}
void ScriptStudio::slotTreeItemDoubleClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (item)
	{
		openTreeItem(item);
	}
}
void ScriptStudio::slotTreeWidgetRightClicked(BObject* object, const BValue& value)
{
	const BPoint& pos = value;
	if (_treeWidget->selectedItemCount() == 1)
	{
		BTreeItem* item = _treeWidget->selectedItem();
		_itemMenu->setAsset(item);
		_itemMenu->setPos(pos);
		_itemMenu->popup();
	}
	else
	{
		BTreeItemArray* items = new BTreeItemArray();
		for (int i = 0; i < _treeWidget->selectedItemCount(); i++)
		{
			*items << _treeWidget->selectedItem(i);
		}
		_itemMenu->setAsset(items);
		_itemMenu->setPos(pos);
		_itemMenu->popup();
	}
}

void ScriptStudio::slotItemEditFocused(BObject* object, const BValue& value)
{
	if (value == false)
	{
		_itemEdit->hide();
	}
}
void ScriptStudio::slotItemTextEdited(BObject* object, const BValue& value)
{
	BValue temp;
	_itemEdit->query("text-size", temp);
	const BSize& textSize = temp;
	int minWidth = textSize.width() + _itemEdit->font()->size();
	BSize csize = _itemEdit->centerSize();
	if (csize.width() < minWidth)
	{
		csize.width() = minWidth;
		_itemEdit->setCenterSize(csize);
	}
}
void ScriptStudio::slotItemEditFinished(BObject* object, const BValue& value)
{
	BTreeItem* item = _itemEdit->asset();
	if (BSource* source = item->asset())
	{
		const BString& text = _itemEdit->text();
		if (text == item->text())
			return;
		SourceInfo* srcinfo = source->asset();
		BString fileName = source->name();
		SourceEdit* edit = (SourceEdit*)_tabWidget->tab(item->text());
		BScript* script = source->script();
		ScriptInfo* sinfo = script->asset();
		BString backupPath;
		BApplication::GetCurrentPath(backupPath);
		BApplication::SetCurrentPath(sinfo->fileName.path());
		if (srcinfo->entry)
		{
			if (BFile::Rename(fileName, text))
			{
				if (edit)
					edit->setTitle(text);
				fileName -= item->text();
				fileName << text;
				source->setName(fileName);
				sinfo->changed = true;
				item->setText(text);
				freshTreeItem(item);
				_saveButton->setEnabled(true);
			}
			else
			{
				BMessageBox::Warning("Error", "Rename source file failed");
			}
		}
		else
		{
			if (edit)
				edit->setTitle(text);
			fileName -= item->text();
			fileName << text;
			source->setName(fileName);
			srcinfo->entry = BEntry::Open(fileName);
			if (srcinfo->entry)
			{
				if (fileName.endWith(".cs"))
				{
					srcinfo->compilable = true;
					source->dirty();
				}
				BString text;
				BFile::Load(fileName, text);
				source->setText(text);
				if (edit)
					edit->setText(text);
			}
			sinfo->changed = true;
			item->setText(text);
			freshTreeItem(item);
			_saveButton->setEnabled(true);
		}
		BApplication::SetCurrentPath(backupPath);
		return;
	}
	if (BFolder* folder = item->asset())
	{
		BFolder::Rename(folder->path(), _itemEdit->text());
		return;
	}
}

void ScriptStudio::slotCurrentTabChanged(BObject* object, const BValue& value)
{
	BWidget* widget = value;
}
void ScriptStudio::slotSourceTextEdited(BObject* object, const BValue& vlaue)
{
	SourceEdit* edit = dynamic_cast<SourceEdit*>(object);
	BSource* source = edit->asset();
	SourceInfo* srcinfo = source->asset();
	if (!edit->title().endWith('*'))
	{
		edit->setTitle(edit->title() + '*');
	}
	_saveButton->setEnabled(true);
}
void ScriptStudio::slotOutputDoubleClicked(BObject* object, const BValue& value)
{
	BPoint pos = value;
	BTextEdit* output = (BTextEdit*)_outputTabWidget->tab("output");
	int line = output->lineAt(pos);
	BString text = output->lineText(line);
	int count = text.toInt();
	int countEnd = text.find('>');
	if (countEnd < text.size())
	{
		text.remove(0, countEnd + 1);
	}
	int fileEnd = text.find(':');
	int end = text.find(':', fileEnd + 1);
	BString fileName = text.substr(0, fileEnd);
	fileName.trimmed();
	int rangeMin = text.find('(', fileEnd + 1, end);
	int rangeMax = text.find(')', rangeMin + 1, end);
	int lineNumber = 0;
	BRange range;
	if (rangeMin < end && rangeMax < end)
	{
		BString lineStr = text.substr(fileEnd + 1, rangeMin);
		BString rangeStr = text.substr(rangeMin + 1, rangeMax);
		lineNumber = lineStr.toInt();
		BStringList words = text.split(',');
		if (words.size() == 2)
		{
			range.min() = words[0].toInt();
			range.max() = words[1].toInt();
		}
	}
	else
	{
		BString lineStr = text.substr(fileEnd + 1, end);
		lineNumber = lineStr.toInt();
	}
	BTextEdit* edit = 0;
	for (int ti = 0; ti < _tabWidget->tabCount(); ti++)
	{
		ScriptBrowser* textEdit = (ScriptBrowser*)_tabWidget->tab(ti);
		if (textEdit->title() == fileName)
		{
			edit = textEdit;
		}
	}
	if (edit == 0)
	{
		BTreeItem* topItem = _treeWidget->topItem(count);
		BScript* script = topItem->asset();
		BTreeItem* item = topItem->locate(fileName);
		edit = openTreeItem(item);
	}
	_tabWidget->setCurrentWidget(edit);
	edit->scrollToLine(lineNumber, Align_Center);
	edit->input("input-line", lineNumber);
	edit->input("input-range", range);
}
void ScriptStudio::slotCreateBreakpoint(BObject* object, const BValue& value)
{
	if (BSource* source = object->asset())
	{
		int line = value;
		BString breakpoint = source->name();
		breakpoint << ':' << line;
		source->script()->insertBreakpoint(breakpoint);
		ScriptInfo* sinfo = source->script()->asset();
		sinfo->changed = true;
		_saveButton->setEnabled(true);
		return;
	}
	if (BScript* script = object->asset())
	{
		int line = value;
		script->insertBreakpoint(line);
		ScriptInfo* sinfo = script->asset();
		sinfo->changed = true;
		_saveButton->setEnabled(true);
		return;
	}
}
void ScriptStudio::slotRemoveBreakpoint(BObject* object, const BValue& value)
{
	if (BSource* source = object->asset())
	{
		int line = value;
		BString breakpoint = source->name();
		breakpoint << ':' << line;
		source->script()->removeBreakpoint(breakpoint);
		_saveButton->setEnabled(true);
		return;
	}
	if (BScript* script = object->asset())
	{
		int line = value;
		script->removeBreakpoint(line);
		_saveButton->setEnabled(true);
		return;
	}
}

void ScriptStudio::updateEvent(const BEvent& event)
{

}
void ScriptStudio::showEvent(const BEvent& event)
{
	BDialog::showEvent(event);

}
void ScriptStudio::closeEvent(const BEvent& event)
{
	if (_saveButton->enabled())
	{
		Button ret = BMessageBox::Question(this, "Animation Edit", "Animation content is changed, do you want save ?", Button_Save | Button_Cancel);
		if (ret == Button_Save)
		{
			slotSaveButtonClicked();
		}
	}
	BDialog::closeEvent(event);
}

void ScriptStudio::resizeEvent(const BEvent& event)
{
	BDialog::resizeEvent(event);
}

void ScriptStudio::styleEvent(const BEvent& event)
{
	BDialog::styleEvent(event);
	if (const BStyle* style = this->realStyle())
	{
		_openButton->setIcon(style->icon("open"));
		_saveButton->setIcon(style->icon("save"));
		_redoButton->setIcon(style->icon("redo"));
		_undoButton->setIcon(style->icon("undo"));
		_searchButton->setIcon(style->icon("search"));
		_buildButton->setIcon(style->icon("build"));
		_debugButton->setIcon(style->icon("debug"));
		_debugResetButton->setIcon(style->icon("debug-reset"));
		_debugCallButton->setIcon(style->icon("debug-call"));
		_debugRunButton->setIcon(style->icon("debug-run"));
		_debugNextButton->setIcon(style->icon("debug-next"));
		_debugStepButton->setIcon(style->icon("debug-step"));
		_debugStopButton->setIcon(style->icon("debug-stop"));

		_itemMenu->menu("add")->setTitleIcon(style->icon("add"));
		_itemMenu->locateAction("add/file")->setIcon(style->icon("new-file"));
		_itemMenu->locateAction("add/folder")->setIcon(style->icon("new-folder"));
		_itemMenu->locateAction("add/script")->setIcon(style->icon("new-script"));
		_itemMenu->menu("new")->setTitleIcon(style->icon("new"));
		_itemMenu->locateAction("new/file")->setIcon(style->icon("new-file"));
		_itemMenu->locateAction("new/folder")->setIcon(style->icon("new-folder"));
		_itemMenu->locateAction("new/script")->setIcon(style->icon("new-script"));
		_itemMenu->action("remove")->setIcon(style->icon("remove"));
		_itemMenu->action("browse")->setIcon(style->icon("browse"));
		_arrowImage = style->image("arrow-right");
		_warnImage = style->image("file-warn");
		if (_warnImage.empty())
		{
			_warnImage = style->font()->image('?');
		}
		for (int i = 0; i < _treeWidget->topItemCount(); i++)
		{
			BTreeItem* topItem = _treeWidget->topItem(i);
			freshTreeItem(topItem);
		}
	}
}
void ScriptStudio::freshEvent(const BEvent& event)
{
	BDialog::freshEvent(event);
}
void ScriptStudio::paintEvent(const BEvent& event)
{
	BDialog::paintEvent(event);

}
